package com.gxa.order.util;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.gxa.order.util.dbfunction.DBFunction;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Component;

import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @User: Administrator
 * @Date: 2023/3/28 - 22:28
 **/

@Component
public class RedisUtils<T> {

    final RedisTemplate redisTemplate;

    @Autowired
    public RedisUtils(RedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    private void setRedisStringRedisTemplateSerializer() {
        this.redisTemplate.setKeySerializer(new StringRedisSerializer());
        this.redisTemplate.setValueSerializer(new StringRedisSerializer());
    }

    /**
     * 从Redis中获取List，如果Redis中没有，则从数据库中获取，并放入Redis中
     *
     * @param prefix     前缀，不需要携带冒号
     * @param type       对象的类型
     * @param expire     过期时间
     * @param timeUnit   过期时间单位
     * @param dbFunction 从数据库中获取对象的方法
     * @return 对象
     */
    public List<T> getListByPageFormRedis(String prefix, Integer currentPage, Integer pageSize, Class<T> type, Integer expire, TimeUnit timeUnit, DBFunction<T> dbFunction) {
        setRedisStringRedisTemplateSerializer();
        String prefixX = prefix + ":";
        // 判断Redis缓存中是否有这个对象，有则返回
        String o = (String) redisTemplate.opsForValue().get(prefixX + currentPage + "_" + pageSize);
        if (StringUtils.isNotBlank(o)) {
            List<T> t = JSONObject.parseArray(o, type);
            return t;
        }
        if (o != null) return null;
        // 从数据库中查询
        List<T> listByPage = dbFunction.getListByPage(currentPage, pageSize);
        if (listByPage == null) {
            // 如果数据库中也没有，则设置空值
            redisTemplate.opsForValue().set(prefixX + currentPage + "_" + pageSize, "", expire, timeUnit);
            return null;
        }
        // 将数据库中查询到的数据放入Redis缓存中
        redisTemplate.opsForValue().set(prefixX + currentPage + "_" + pageSize, JSONObject.toJSONString(listByPage, SerializerFeature.DisableCircularReferenceDetect), expire, timeUnit);
        return listByPage;
    }

    /**
     * 从Redis中获取对象，如果Redis中没有，则从数据库中获取，并放入Redis中
     *
     * @param prefix     前缀，不需要携带冒号
     * @param id         对象的id
     * @param type       对象的类型
     * @param expire     过期时间
     * @param timeUnit   过期时间单位
     * @param dbFunction 从数据库中获取对象的方法
     * @param <T>        对象的类型
     * @return 对象
     */
    public <T> T getByIdFromRedis(String prefix, Long id, Class<T> type, Integer expire, TimeUnit timeUnit, DBFunction<T> dbFunction) {
        setRedisStringRedisTemplateSerializer();
        String prefixX = prefix + ":";
        // 判断Redis缓存中是否有这个对象，有则返回
        String o = (String) redisTemplate.opsForValue().get(prefixX + id);
        if (StringUtils.isNotBlank(o)) {
            T t = JSONObject.toJavaObject(JSONObject.parseObject(o), type);
            return t;
        }
        if (o != null) {
            // 说明Redis中有这个key，但是值为null，是缓存的空值
            return null;
        }
        // 从数据库中查询
        T dbObject = dbFunction.getById(id);
        if (dbObject == null) {
            // 如果数据库中也没有，则设置空值
            redisTemplate.opsForValue().set(prefixX + id, "", expire, timeUnit);
            return null;
        }
        // 将数据库中查询到的数据放入Redis缓存中
        redisTemplate.opsForValue().set(prefixX + id, JSONObject.toJSONString(dbObject, SerializerFeature.DisableCircularReferenceDetect), expire, timeUnit);
        return dbObject;
    }


    public List<T> getListFromRedis(String prefix, Class<T> type, Integer expire, TimeUnit timeUnit, DBFunction<T> dbFunction) {
        setRedisStringRedisTemplateSerializer();
        String prefixX = prefix + ":";
        // 判断Redis缓存中是否有这个对象，有则返回
        String o = (String) redisTemplate.opsForValue().get(prefixX);
        if (StringUtils.isNotBlank(o)) {
            List<T> t = JSONObject.parseArray(o, type);
            return t;
        }
        if (o != null) {
            // 说明Redis中有这个key，但是值为null，是缓存的空值
            return null;
        }
        // 从数据库中查询
        List<T> dbObject = dbFunction.getList();
        if (dbObject == null) {
            // 如果数据库中也没有，则设置空值
            redisTemplate.opsForValue().set(prefixX, "", expire, timeUnit);
            return null;
        }
        // 将数据库中查询到的数据放入Redis缓存中
        redisTemplate.opsForValue().set(prefixX, JSONObject.toJSONString(dbObject, SerializerFeature.DisableCircularReferenceDetect), expire, timeUnit);
        return dbObject;
    }

    public T getObjectFromRedis(String prefix, Class<T> type, Integer expire, TimeUnit timeUnit, DBFunction<T> dbFunction) {
        setRedisStringRedisTemplateSerializer();
        String o = (String) redisTemplate.opsForValue().get(prefix);
        if (StringUtils.isNotBlank(o)) {
            T t = JSONObject.parseObject(o, type);
            return t;
        }
        if (o != null) {
            // 说明Redis中有这个key，但是值为null，是缓存的空值
            return null;
        }
        // 从数据库中查询
        T dbObject = dbFunction.getObject();
        if (dbObject == null) {
            // 如果数据库中也没有，则设置空值
            redisTemplate.opsForValue().set(prefix, "", expire, timeUnit);
            return null;
        }
        // 将数据库中查询到的数据放入Redis缓存中
        redisTemplate.opsForValue().set(prefix, JSONObject.toJSONString(dbObject, SerializerFeature.DisableCircularReferenceDetect), expire, timeUnit);
        return dbObject;
    }

    /**
     * 查看Redis中是否有这个key
     *
     * @param keyName key
     * @return 是否有这个KEY，有则返回true，否则返回false
     */
    public boolean hasKey(String keyName) {
        return redisTemplate.opsForValue().getOperations().hasKey(keyName);
    }


    public <T> List<T> getAsList(String keyName) {
        return (List<T>) redisTemplate.opsForValue().get(keyName);
    }

    public <T> List<T> getStringAsList(String keyName, Class<T> type) {
        String s = (String) redisTemplate.opsForValue().get(keyName);
        return JSONObject.parseArray(s, type);
    }

    public RedisTemplate getRedisTemplate() {
        return redisTemplate;
    }

    public void putObjectToRedis(String archiveYear, List<T> listBlog, int i, TimeUnit timeUnit) {
        setRedisStringRedisTemplateSerializer();
        redisTemplate.opsForValue().set(archiveYear, JSONObject.toJSONString(listBlog), i, timeUnit);
    }

    public void setStringKV(String key, String value, int expire, TimeUnit timeUnit) {
        setRedisStringRedisTemplateSerializer();
        redisTemplate.opsForValue().set(key, value, expire, timeUnit);
    }

    public void clearAllRedisCache() {
        Set<String> keys = new HashSet<>();
        keys.addAll(redisTemplate.keys("*"));
        redisTemplate.delete(keys);
    }


    private LinkedList<String> list = new LinkedList<>();

    public RedisUtils clearRedisCache(String s) {
        Set<String> keys = new HashSet<>();
        keys.addAll(redisTemplate.keys(s));
        redisTemplate.delete(keys);
        return this;
    }

    public RedisUtils add(String s) {
        list.add(s);
        return this;
    }

}
